package com.zhdl.modules.iiiiiii.jSerialCommTest;

import cn.hutool.core.util.HexUtil;
import com.fazecast.jSerialComm.SerialPort;
import com.fazecast.jSerialComm.SerialPortDataListener;
import com.fazecast.jSerialComm.SerialPortEvent;
import com.zhdl.common.ytools.callback.CommonCallback;
import lombok.extern.slf4j.Slf4j;

import java.util.LinkedHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
public class SerialPortManager {

    private static SerialPortManager instance = null;
    private final LinkedHashMap<String, SimpleSerialPort> serialPortLinkedHashMap = new LinkedHashMap<>();
    private boolean isOpen = true;
    private final int sendIdMax = 999;

    //获取instance实例
    synchronized public static SerialPortManager getInstance() {
        if (instance == null) {
            instance = new SerialPortManager();

        }
        return instance;
    }

    private SerialPortManager() {

    }

    public boolean addPort(String port, int baudRate, int timeOut) {
        SerialPort serialPort = SerialPort.getCommPort(port);// 替换为你的端口名
        serialPort.setComPortParameters(baudRate, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); // 设置端口参数
        serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1, 5);
        if (serialPort.openPort()) {
            System.out.println("Port opened successfully.");
            SimpleSerialPort simpleSerialPort = new SimpleSerialPort();
            simpleSerialPort.setSerialPort(serialPort);
            simpleSerialPort.setSerialPortDataLinkedList(new CopyOnWriteArrayList<>());
            simpleSerialPort.setReceiverId(0);
            simpleSerialPort.setTimeOut(timeOut);
            serialPortLinkedHashMap.put(port, simpleSerialPort);
            addDateListener(serialPort);
            return true;
        } else {
            System.out.println("Unable to open the port.");
            return false;
        }
    }

    String dataAll = "";

    private void addDateListener(SerialPort serialPort) {
        serialPort.addDataListener(new SerialPortDataListener() {
            @Override
            public int getListeningEvents() {
                return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
            }

            @Override
            public void serialEvent(SerialPortEvent event) {
                if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
                    // 接收数据
                    byte[] readBuffer = new byte[1024]; // 调整数组大小以适应预期的响应长度
                    int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
                    if (numRead > 0) {
                        // 将读取的字节转换为十六进制字符串
                        StringBuilder data = new StringBuilder();
                        for (int i = 0; i < numRead; i++) {
                            data.append(String.format("%02X ", readBuffer[i]));
                        }

                        try {
                            SimpleSerialPort simpleSerialPort = null;
                            for (String s : serialPortLinkedHashMap.keySet()) {
                                SimpleSerialPort simpleSerialPort1 = serialPortLinkedHashMap.get(s);
                                if (simpleSerialPort1.serialPort.equals(event.getSerialPort())) {
                                    simpleSerialPort = simpleSerialPort1;
                                    break;
                                }
                            }
                            if (simpleSerialPort != null) {
                                simpleSerialPort.setLastReceiveTime(System.currentTimeMillis());
                                CopyOnWriteArrayList<SerialPortData> sendQueen = simpleSerialPort.getSerialPortDataLinkedList();
                                SerialPortData serialPortData = null;
                                for (SerialPortData item : sendQueen) {
                                    if (item.getSendId() == simpleSerialPort.receiverId) {
                                        serialPortData = item;
                                    }
                                }
                                dataAll = dataAll + data.toString();
                                if (dataAll.length() <= 180){
                                    log.info("dataAll <= 180");
                                    return;
                                }

                                if (serialPortData == null) {
                                    log.info("serialPortData == null");
                                    return;
                                }
                                serialPortData.getCallback().statusCallback(dataAll + "---sendId" + serialPortData.getSendId() + "---发送指令" + serialPortData.getSendCmd() + "---receiverId" + simpleSerialPort.getReceiverId());
                                simpleSerialPort.receiverId++;
                                sendQueen.remove(serialPortData);
                                if (simpleSerialPort.receiverId > sendIdMax) {
                                    simpleSerialPort.receiverId = 0;
                                }
                                dataAll = "";
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        // System.out.println("Received data: " + data.toString());
                        // 在这里进行收到数据的处理操作，例如加入阻塞队列，另一个模块消费队列解析收到的数据
                    }
                }
            }
        });
    }

    public synchronized boolean sendDate(String port, byte[] date, CommonCallback<String> callback) {
        if (serialPortLinkedHashMap.get(port) != null) {
            int sendId = serialPortLinkedHashMap.get(port).getSendId();
            if (sendId >= sendIdMax) {
                serialPortLinkedHashMap.get(port).setSendId(0);
            } else {
                serialPortLinkedHashMap.get(port).setSendId(sendId + 1);
            }
            return sendDate(port, date, callback, serialPortLinkedHashMap.get(port).getTimeOut(), sendId);
        } else {
            return false;
        }
    }

    public synchronized boolean sendDate(String port, byte[] date, CommonCallback<String> callback, int sendId) {
        if (serialPortLinkedHashMap.get(port) != null) {
            return sendDate(port, date, callback, serialPortLinkedHashMap.get(port).getTimeOut(), sendId);
        } else {
            return false;
        }
    }

    public synchronized boolean sendDate(String port, byte[] date, CommonCallback<String> callback, int timeOut, int sendId) {
        if (serialPortLinkedHashMap.get(port) == null) {
            log.info(port + "发送指令>>>>" + HexUtil.encodeHexStr(date) + "失败!!!!because---serialPortLinkedHashMap.get(port) == null");
            return false;
        }
        SerialPort serialPort = serialPortLinkedHashMap.get(port).serialPort;
        if (serialPort == null) {
            log.info(port + "发送指令>>>>" + HexUtil.encodeHexStr(date) + "失败!!!!because---serialPortLinkedHashMap.get(port).serialPort == null");
            return false;
        }
        SerialPortData serialPortData = new SerialPortData();
        serialPortData.setSendId(sendId);
        serialPortData.setCallback(callback);
        serialPortData.setSendCmd(HexUtil.encodeHexStr(date));
        serialPortLinkedHashMap.get(port).getSerialPortDataLinkedList().add(serialPortData);
        serialPort.writeBytes(date, date.length);
        if (serialPortLinkedHashMap.get(port).getLastReceiveTime() == 0) {
            serialPortLinkedHashMap.get(port).setLastReceiveTime(System.currentTimeMillis());
        }
        serialPortLinkedHashMap.get(port).setTimeOut(timeOut);
        serialPortLinkedHashMap.get(port).setLastSendTime(System.currentTimeMillis());
        log.info(port + "发送指令>>>>" + HexUtil.encodeHexStr(date) + "成功!!!! sendId = " + sendId);
        checkQueenTimeOut();
        return true;
    }

    private void checkQueenTimeOut() {
        if (serialPortLinkedHashMap.keySet().size() > 0) {
            for (String s : serialPortLinkedHashMap.keySet()) {
                if (serialPortLinkedHashMap.get(s).getSerialPortDataLinkedList().size() > 0) {
                    long lastSendTime = serialPortLinkedHashMap.get(s).getLastSendTime();
                    long lastReceiveTime = serialPortLinkedHashMap.get(s).getLastReceiveTime();
                    int timeOut = serialPortLinkedHashMap.get(s).getTimeOut();
                    if (lastSendTime - lastReceiveTime > timeOut) {
                        serialPortLinkedHashMap.get(s).setLastReceiveTime(System.currentTimeMillis());
                        log.info(s + "有超时的消息!!!! ");
                        if (serialPortLinkedHashMap.get(s).serialPortDataLinkedList.size() >= (sendIdMax / 10)) {
                            log.info(s + "超时消息达到最大限度清除队列....");
                            serialPortLinkedHashMap.get(s).serialPortDataLinkedList.clear();
                        }
                        log.info(s + "等待指令回调队列长度>>>" + serialPortLinkedHashMap.get(s).getSerialPortDataLinkedList().size());
                    }
                }
            }
        }
    }

}
